package com.ywh.floating.view

import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Point
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.FrameLayout
import com.ywh.floating.FloatingConfig
import com.ywh.floating.TouchHelper
import com.ywh.floating.ext.flog

/**
 * Create by yangwenhao on 2022/8/5
 */
@SuppressLint("ViewConstructor")
class FloatingView(content: Context, attributeSet: AttributeSet?, var config: FloatingConfig) : FrameLayout(content, attributeSet) {
    private var layoutId: Int = config.mLayoutId
    var moveUpdateListener: ((Int, Int) -> Unit)? = null
    private var maxWidth: Int = 0
    private var maxHeight: Int = 0
    private var floatingWidth = 0
    private var floatingHeight = 0
    private val mLocation = Point(config.initialX, config.initialY)
    private val mTouchSlop = context.resources.displayMetrics.density * 8F
    private var valueAnimator: ValueAnimator? = null
    private var animatorEndX = 0
    private val mTouchHelper: TouchHelper

    init {
        var childView = inflate(content, layoutId, this)
        config.rootViewCallback?.invoke(this)

        mTouchHelper = TouchHelper(this, mTouchSlop, { movedX, moveY ->
            val newX = mLocation.x + movedX
            val newY = mLocation.y + moveY
            moveUpdateListener?.invoke(limitHandlerX(newX), limitHandlerY(newY))
        }, {
            val lp = layoutParams as? FrameLayout.LayoutParams ?: return@TouchHelper
            updateLocation(lp.leftMargin, lp.topMargin)
            if (config.mSuctionEdge) {
                startSuctionEdge()
            }
        }, {
        })
    }

    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
        return mTouchHelper.onInterceptTouchEvent(ev)
    }

    internal fun maxSize(maxWidth: Int, maxHeight: Int) {
        this.maxWidth = maxWidth
        this.maxHeight = maxHeight
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        floatingWidth = measuredWidth
        floatingHeight = measuredHeight
        //        flog(this::class.java, "floatingWidth:${floatingWidth},floatingHeight:${floatingHeight}")
    }

    /**
     * 吸边动画
     */
    private fun startSuctionEdge() {
        valueAnimator = if (mLocation.x < maxWidth - mLocation.x - floatingWidth) {
            ValueAnimator.ofInt(mLocation.x, 0)
        } else {
            animatorEndX = maxWidth - floatingWidth
            ValueAnimator.ofInt(mLocation.x, maxWidth - floatingWidth)
        }
        valueAnimator?.apply {
            addUpdateListener {
                val animatorValue = (it.animatedValue as? Int) ?: return@addUpdateListener
                updateLocation(limitHandlerX(animatorValue.toFloat()), limitHandlerY(mLocation.y.toFloat()))
                moveUpdateListener?.invoke(mLocation.x, mLocation.y)
            }
            startDelay = 50
            duration = 200
            start()
        }
    }

    private fun updateLocation(x: Int, y: Int) {
        mLocation.x = x
        mLocation.y = y
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        flog(FloatingView::class.java, "onDetachedFromWindow:${animatorEndX}")
        valueAnimator?.apply {
            cancel()
            removeAllUpdateListeners()
        }
        valueAnimator = null
        updateLocation(limitHandlerX(animatorEndX.toFloat()), limitHandlerY(mLocation.y.toFloat()))
        moveUpdateListener?.invoke(mLocation.x, mLocation.y)
    }

    //边界处理
    private fun limitHandlerX(x: Float): Int {
        if (x < 0) return 0
        if (floatingWidth + x > maxWidth) {
            return maxWidth - floatingWidth
        }
        return x.toInt()
    }

    private fun limitHandlerY(y: Float): Int {
        if (y < 0) return 0
        if (floatingHeight + y > maxHeight) {
            return maxHeight - floatingHeight
        }
        return y.toInt()
    }
}